package org.bootstrap.service.Impl;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.signers.JWTSigner;
import org.bootstrap.annotation.TokenValidate;
import org.bootstrap.entity.UserInfo;
import org.bootstrap.mapper.UserMapper;
import org.bootstrap.service.UserService;
import org.bootstrap.tool.BooleanOptional;
import org.bootstrap.tool.RedisTool;
import org.bootstrap.tool.Tool;
import org.bootstrap.types.Random;
import org.bootstrap.types.RegRules;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Lazy
@Service
public class UserServiceImpl extends UserService {
    @SuppressWarnings("unused")
    @Resource
    private UserMapper userMapper;
    @SuppressWarnings("unused")
    @Resource
    private Tool tool;
    @SuppressWarnings("unused")
    @Resource
    private RedisTool redisTool;

    private static final long token_time = 30;

    @Autowired
    private UserServiceImpl self;

    @Override
    public int user_sign(HashMap<String, Object> user) {
        int code;
        if (user.isEmpty()) {
            Console.error("列表空");
            code = 400;
        }
        if (user.containsKey("account") && user.containsKey("name") && user.containsKey("password")) {
            String account = user.getOrDefault("account", "").toString();
            String password = user.getOrDefault("password", "").toString();
            String name = user.getOrDefault("name", "").toString();
            name = HtmlUtil.filter(name); // 过滤非法字符
            // 验证用户名
            if (RegRules.validate(RegRules.REG_USER, account) && RegRules.validate(RegRules.REG_PASSWORD, password)) {
                HashMap<String, Object> safe_data = new HashMap<>();
                //用户随机ID
                String user_id = RandomUtil.randomString(Random.NumberChar, 6);
                safe_data.put("user_id", user_id);
                safe_data.put("name", name);
                safe_data.put("account", account);
                safe_data.put("password", password);
                safe_data.put("pinyin", tool.get_first_char(name).replaceAll(",", "")); // 获取首字母拼音
                try {
                    code = userMapper.user_sign(safe_data) > 0 ? 200 : 400;
                } catch (UncategorizedSQLException sqlException) {
                    sqlException.getMessage();
                    code = 500;
                } catch (DuplicateKeyException ignored) {
                    code = 300;
                }
            } else {
                code = 400;
            }
        } else {
            code = 400;
        }
        return code;
    }

    // 用户登录 控制权限
    @Override
    public JSONObject user_login(HashMap<String, String> params) {
        JSONObject token = JSONUtil.createObj();
        if (Objects.isNull(params) || params.isEmpty()) token.putOpt("code", 400);
        if (params.containsKey("account") && params.containsKey("password")) {
            String account = params.getOrDefault("account", null);
            String password = params.getOrDefault("password", null);
            if (StrUtil.isNotEmpty(account) && StrUtil.isNotEmpty(password)) {
                HashMap<String, String> form = new HashMap<>();
                form.put("account", account);
                form.put("password", password);
                String uid = userMapper.user_login(form);// 拿到用户id 私密
                if (StrUtil.isNotEmpty(uid)) {
                    try {
                        String encrypt_uid = tool.Encrypt(uid);// 加密后的uid
                        String str_token = tool.createToken("id", encrypt_uid, token_time);// 生成token xx 天后过期
                        token.putOpt("code", 200)
                                .putOpt("token", str_token);//登录成功后将用户信息保存到缓存中
                        redisTool.save_string(uid, str_token, 5, TimeUnit.DAYS); // 自动保留五天
                    } catch (UnsupportedEncodingException ignore) {
                        token.putOpt("code", 500);
                        redisTool.del_string(uid); // 删除缓存 如果登录失败
                        Console.error("UserServiceImpl:109\t", "不支持的加密编码");
                    }
                } else {
                    token.putOpt("code", 300);// 密码错误
                }
            }
        } else {
            token.putOpt("code", 400);
        }
        return token;
    }

    @Override
    public ArrayList<HashMap<String, Object>> user_search(HashMap<String, String> params) {
        if (params.isEmpty()) {
            return null;
        } else if (params.containsKey("keyword")) {
            String keyword = params.getOrDefault("keyword", null);
            if (StrUtil.isNotEmpty(keyword)) {
                ArrayList<HashMap<String, Object>> user_list = userMapper.user_search(keyword);
                user_list.forEach(item -> {
                    String name = StrUtil.toString(item.get("name"));// 获取字符串 然后切割为单个字符 获取其首字母
                    String[] names = name.split("");
                    JSONArray array = JSONUtil.createArray();// 外包裹
                    for (String _char : names) {
                        JSONObject chars = JSONUtil.createObj();
                        char letter = PinyinUtil.getFirstLetter(_char.charAt(0));
                        chars.putOpt("letter", letter)
                                .putOpt("chinese", _char);
                        array.add(chars);
                    }
                    item.put("high_light", array);
                }); // 处理高亮
                return user_list;
            }
            return null;
        } else {
            return null;
        }
    }

    @Override
    public JSONObject info_modify(HashMap<String, String> params) {
        JSONObject res = JSONUtil.createObj();
        int code = 0;
        String msg = "暂无";
        if (params.isEmpty()) {
            code = 404;
        } else {
            String str_token = params.get("token");// 获取token
            if (StrUtil.isNotEmpty(str_token)) {
                if (verity_token(str_token)) {
                    JSONObject verity_res = verity_token_width_db(str_token, true);// 连接服务器验证
                    if (verity_res.getBool("success")) {
                        String user_id = verity_res.getStr("user_id");
                        params.remove("token");
                        String options = params.get("options");
                        JSONObject option = JSONUtil.parseObj(options);
                        String name = option.getStr("name");
                        String pinyin = tool.get_first_char(name).replaceAll(",", ""); // 去掉所有逗号
                        option.putOpt("pinyin", pinyin); // 生成拼音
                        Console.log(pinyin);
                        option.keySet().forEach(item -> params.put(item, option.getStr(item)));
                        params.put("user_id", user_id);
                        int rows = userMapper.info_modify(params);// 写入数据库
                        code = rows > 0 ? 200 : 302;
                        msg = rows > 0 ? "修改成功" : "修改失败";
                    } else {
                        code = 300;
                        msg = "用户登录状态异常";
                    }
                } else {
                    code = 405;
                    msg = "Token 验证失败";
                }
            } else {
                code = 405;
                msg = "Token 验证失败";
            }
        }
        res.putOpt("code", code)
                .putOpt("msg", msg);
        return res;
    }


    @Override
    public JSONObject admin(HashMap<String, String> params) {
        return null;
    }


    /**
     * @param data{ token:str }
     * @return obj
     */
    public JSONObject user_info(HashMap<String, String> data, boolean show_uid) {
        JSONObject obj = JSONUtil.createObj();
        if (data.isEmpty()) {
            obj.putOpt("login", false).putOpt("code", 400);
        } else if (data.containsKey("token")) {
            String token = data.getOrDefault("token", null);
            if (StrUtil.isNotEmpty(token)) {
                // 校验token 合法性
                boolean pass = tool.verityToken(token);
                if (pass) { // 解析token
                    JWT jwt = tool.parseToken(token);
                    String str_payload = jwt.getPayload("id").toString();
                    String uid = tool.Decrypt(str_payload);
                    UserInfo user_info = get_user_info(uid);
                    if (Objects.isNull(user_info)) {
                        redisTool.del_string(uid);// 删除缓存
                        obj.putOpt("login", false).putOpt("code", 300);// 300 过期了
                    } else {
                        if (!show_uid) {
                            user_info.setUser_id(null);
                        }
                        if (redisTool.hasKey(uid)) {
                            String token_cache = redisTool.get_string(uid);
                            if (show_uid && verity_token(token_cache)) {
                                obj.putOpt("author_id", uid);
                            }
                            obj.putOpt("login", verity_token(token_cache));
                        } else {
                            obj.putOpt("login", false);
                        }
                        obj.remove("access");
                    }
                } else {
                    obj.putOpt("login", false).putOpt("code", 300);
                }
            }
        } else {
            obj.putOpt("login", false).putOpt("code", 300);
        }
        return obj;
    }

    public UserInfo get_user_info(String uid) {
        if (StrUtil.isEmpty(uid)) {
            return null;
        }
        return userMapper.user_info(uid);
    }

    //  验证token
    private boolean verity_token(CharSequence str) {
        if (StrUtil.isEmpty(str)) return false;
        return tool.verityToken(str.toString());
    }

    // 解析token
    private JSONObject parse_token(CharSequence str) {
        JSONObject object = JSONUtil.createObj();
        if (StrUtil.isEmpty(str)) {
            object.putOpt("pass", false);
        } else {
            JWT jwt = tool.parseToken(str.toString());
            String payload = jwt.getPayload("id").toString();
            JWTSigner signer = jwt.getSigner();
            object.putOpt("payload", payload)
                    .putOpt("signer", signer);
        }
        return object;
    }

    /**
     * 验证用户并和缓存对比
     *
     * @param token 令牌文本
     * @return {success:bool,token:string,token_payload:string}
     */
    public JSONObject verity_token_width_db(String token, boolean connect_db) {
        if (StrUtil.isEmpty(token)) {
            return null;
        }
        JSONObject info = JSONUtil.createObj();
        if (verity_token(token)) {
            JSONObject parse_token = parse_token(token); // 解析token
            String payload = parse_token.getStr("payload");
            if (connect_db) {  //如果需要连接数据库并验证账号
                String user_id = tool.Decrypt(payload);// 解密出玩家id
                boolean exit = userMapper.user_exit(user_id) == 1; // 数据库是否存在用户
                if (exit) {
                    info.putOpt("token", token).
                            putOpt("user_id", user_id).
                            putOpt("success", true);
                } else { // 用户不存在
                    info.putOpt("token", token).
                            putOpt("user_id", user_id).
                            putOpt("success", false);
                }
            } else {
                info.putOpt("success", false).
                        putOpt("token", token).putOpt("user_id", null);
            }
        } else {
            Console.error("token 已过期");
        }
        return info;
    }

    /**
     * 用户退出登录状态
     *
     * @param token 令牌
     * @return json
     */

    public JSONObject user_logout(String token) {
        JSONObject json = JSONUtil.createObj();
        int code = 500;
        String msg = "退出失败";
        if (StrUtil.isNotEmpty(token)) {
            boolean valid = tool.verityToken(token);// 验证令牌
            if (valid) {
                JWT _token = tool.parseToken(token); // 获取用户id
                Object id = _token.getPayload("id");
                if (!Objects.isNull(id)) {
                    String user_id = StrUtil.toString(id);
                    if (StrUtil.isNotEmpty(user_id)) {
                        String _user_id = tool.Decrypt(user_id); // 解析加密文本
                        if (StrUtil.isNotEmpty(_user_id)) {
                            redisTool.del_string(_user_id);// 删除缓存
                            code = 200;
                            msg = "退出成功";
                        } else {
                            // 照样退出
                            code = 400;
                            msg = "登录已过期";
                        }
                    } else {
                        // 照样退出
                        code = 400;
                        msg = "登录已过期";
                    }
                } else {
                    // 照样退出
                    code = 400;
                    msg = "登录已过期";
                }
            } else {
                // 令牌过期照样退出
                code = 400;
                msg = "登录已过期";
            }
        }
        json.putOpt("code", code)
                .putOpt("msg", msg);
        return json;
    }

    /**
     * 修改用户头像
     *
     * @param user_id 用户id
     * @param name    文件名字
     */
    public boolean update_avg(String user_id, String name) {
        return userMapper.update_avg(name, user_id) > 0; // 注意交换参数顺序
    }

    public boolean is_admin(String userId) {
        return userMapper.is_admin(userId) > 0;
    }

    @TokenValidate(value = "params", fileds = "token", auth_check = true)
    public JSONObject user_verity(HashMap<String, String> params) {
        return null;
    }

    @Override
    public ArrayList<UserInfo> allUsr() {
        return userMapper.allUsr();
    }

    public JSONObject modify_password(HashMap<String, String> params) {
        JSONObject verity = self.user_verity(params);
        UserInfo userInfo = verity.get("user_info", UserInfo.class);
        verity.clear();
        if (Objects.isNull(userInfo)) {
            verity.putOpt("code", 404); // 传输字段为空
        } else {
            String userId = userInfo.getUser_id();
            BooleanOptional.of(StrUtil.isNotEmpty(userId))
                    .isTrue(t -> {
                        String origin = params.getOrDefault("origin", "");
                        String repassword = params.getOrDefault("repassword", "");
                        String newpassord = params.getOrDefault("newpassword", "");
                        if (StrUtil.isNotEmpty(origin)) {
                            boolean rows = userMapper.verity_password(userId, origin) > 0;// 和数据库第一次握手
                            if (rows) {
                                verity.putOpt("code", 200);
                            } else {
                                verity.putOpt("code", 400); // 密码原密码不相同
                            }
                        } else if (StrUtil.isNotEmpty(repassword) && StrUtil.isNotEmpty(newpassord) && StrUtil.equals(repassword, newpassord)) {
                            int rows = userMapper.modify_password(userId, repassword);
                            verity.putOpt("code", rows > 0 ? 200 : 400); // 原密码为空或者不合法
                        } else {
                            verity.putOpt("code", 401); // 原密码为空或者不合法
                        }
                    }).isFalse(f -> {
                        verity.putOpt("code", 402); // 用户状态异常
                    }).isFalse(g -> {
                        verity.putOpt("code", 403);//用户状态异常
                    });
        }
        return verity;
    }

    @Override
    public ArrayList<UserInfo> get_all_users(HashMap<String, String> params) {
        int _page = 0;
        if (Objects.nonNull(params) && !params.isEmpty()) {
            _page = NumberUtil.parseInt(params.getOrDefault("page", "0"));
        }
        int pageSize = 8;
        int start;
        int end;
        int[] index = PageUtil.transToStartEnd(_page, pageSize);
        start = index[0];
        end = pageSize;
        return userMapper.get_all_users(start, end);
    }
}
